﻿//#define POKEMONDEMO
using Sirenix.OdinInspector;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;

#region Warehouse-Item Define
public class PWarehouse : MonoBehaviour
{
    public static bool validate = false;
    public static Dictionary<string, WareHouseInfo> globalIndex = new Dictionary<string, WareHouseInfo>();
    public static List<Dictionary<string, PWareItem>> globalRoster = new List<Dictionary<string, PWareItem>>();

    /// <summary>
    /// 作为自动进行的全局仓库入口点, 只需要添加AddRoster(pwareItem,IpwareRoster) , 并各自实现就可以了
    /// </summary>
    public void InitWarehouse()
    {
#if POKEMONDEMO
        AddRoster<BasicOrder, BasicOrderRoster>();
        AddRoster<LLMMethod, Roster_LLMMethod_Normal>();
        AddRoster<LLMMethod_Battle, Roster_LLMMethod_Battle>();
        AddRoster<POrder1, Roster_POrder1>();
#endif
        validate = true;

#if UNITY_EDITOR
        EditorApplication.playModeStateChanged += (state) =>
        {
            if (state == PlayModeStateChange.ExitingPlayMode) ClearWarehouse();
        };
#endif
    }


    public void ClearWarehouse()
    {
        validate = false;
        globalIndex.Clear();
        for (int i = 0; i < globalRoster.Count; i++)
        {
            globalRoster[i].Clear();
            globalRoster[i] = null;
        }
        globalRoster.Clear();
    }

    /// <summary>
    /// 也就是说在注册名单的时候, Name是短名称, ToString是长名称, 后者可以起到命名空间限定的作用
    /// </summary>
    /// <param name="type"></param>
    /// <exception cref="Exception"></exception>
    public static void AddRoster(Type type, Type pwareRoster)
    {
        if (type.GetInterface("IPWareRegisteable") == null) throw new Exception("该类没有继承自PwareItem,无法加入仓库!");

        var info = new WareHouseInfo()
        {
            name = type.Name,
            type = type,
            index = globalRoster.Count,
        };

        if (globalIndex.ContainsKey(type.Name)) throw new Exception("该类已加入过仓库!");
        globalIndex.Add(type.Name, info);
        globalRoster.Add(new Dictionary<string, PWareItem>());

        //初始化roster 
        IPwareRoster roster = Activator.CreateInstance(pwareRoster) as IPwareRoster;
        if (roster == null) throw new Exception("传入的Roster不合法或者没有实现 IPWareRegisteable");
        roster.DefineRoster();
    }

    /// <summary>
    /// 这个地方两个泛型约束所表达的意义是有待商榷的, 虽然都实现了功能, 但是设计语言是不同的
    /// 要么都用类, 要么都用接口, 等待后续的感悟
    /// </summary>
    /// <typeparam name="T1"></typeparam>
    /// <typeparam name="T2"></typeparam>
    public static void AddRoster<T1, T2>() where T1 : PWareItem where T2 : IPwareRoster => AddRoster(typeof(T1), typeof(T2));

    public static void AddItem(Type type, PWareItem pitem)
    {
        if (globalIndex.TryGetValue(type.Name, out var info))
        {
            var roster = globalRoster[info.index];
            //目前的逻辑是粗暴的覆盖
            roster[pitem.name] = pitem;
        }
    }
    public static PWareItem GetItem(Type type, string name)
    {
        if (globalIndex.TryGetValue(type.Name, out var info))
        {
            var roster = globalRoster[info.index];
            if (roster.ContainsKey(name)) return roster[name];
            return null;
        }
        return null;
    }
    public static T GetItem<T>(string name) where T : PWareItem
    {
        Type type = typeof(T);
        if (globalIndex.TryGetValue(type.Name, out var info))
        {
            var roster = globalRoster[info.index];
            if (roster.ContainsKey(name)) return (T)roster[name];
        }
        return null;
    }

    public static IEnumerable<PWareItem> GetRoster<T>()
    {
        Type type = typeof(T);
        if (globalIndex.TryGetValue(type.Name, out var info))
        {
            var roster = globalRoster[info.index];
            if (roster != null)
                return roster.Values.ToList();
        }
        return null;
    }

    public static void PrintAllItem()
    {
        string o = "AllItems:\n";
        int count = 0;
        foreach (var roster in globalRoster)
        {
            foreach (var item in roster.Values)
            {
                o += $"{++count}:{item.name},\n";
            }
        }
        Debug.Log(o);
    }
    [Button]
    public void DebugPrintAllItem()
    {
        PrintAllItem();
    }

    public class WareHouseInfo
    {
        public string name;
        public int index;
        public Type type;

    }
}

public interface IPWareRegisteable
{
    public void RegisteToWarehouse();
}
public interface IPwareRoster
{
    public void DefineRoster();
}
public interface IRosterExtensionable
{
    public PWareItem DefineRoster();
}
public abstract class PWareItem : IPWareRegisteable
{
    public string name;
    public PWareItem(string name)
    {
        this.name = name;
        RegisteToWarehouse();
    }

    public void RegisteToWarehouse()
    {
        PWarehouse.AddItem(this.GetType(), this);
    }

    public PWareItem GetItem(string name)
    {
        Type type = this.GetType();
        return PWarehouse.GetItem(type, name);
    }

}
#endregion
